/******************************************************************************
* WOR on CC430 Code Example - TX, RX & WOR (variable packet length =< FIFO size)
*
* Simple demonstration of WOR implementation on CC430 
* Warning: This RF code example is setup to operate at 868MHz or 915Mhz 
* frequency depending on the build configuration, which might be out of 
* allowable range of operation in certain countries. 
* Please refer to the appropriate legal sources before performing tests with 
* this code example. 
* 
* This code example can be loaded to 2 CC430 devices. The first device can be 
* selected to operate in TX Mode, periodically transmitting an RF packet. The 
* second device can be selected to operate in either RX or WOR mode. 
* 
* The RF packet engine settings specify variable-length-mode with CRC check 
* enabled. The RX packet also appends 2 status bytes regarding CRC check, RSSI 
* and LQI info. For specific register settings please refer to the comments for 
* each register in RfRegSettings.c, the CC430x613x User's Guide, and/or 
* SmartRF Studio.
* 
* D. Dang
* Texas Instruments Inc.
* March 2010
* Built with IAR Embedded Workbench Version: 4.21
******************************************************************************/

#include "TX_RX_WOR.h"
#include "hal_UCS.h"
#include "hal_pmm.h"
#include "cc430f6135.h"
//#include "inttypes.h"
//#include "msp430.h"

#define B1 (P1IN & BIT2)
#define SUCCESS 1
#define FAIL 0
#define CUTDOWN 0x00000000

#define  PACKET_LEN         (0x05)
#define  RSSI_IDX           (PACKET_LEN+1)  // Index of appended RSSI 
#define  CRC_LQI_IDX        (PACKET_LEN+2)  // Index of appended LQI, checksum
#define  CRC_OK             (BIT7)          // CRC_OK bit 
#define  PATABLE_VAL        (0x51)          // 0 dBm output 

#define  MODE_NOT_SET       0
#define  PACKET_RX          3
#define  PACKET_TX          4
#define  PACKET_RX_WOR      5

#define  BIT15              0x8000
#define  BIT14              0x4000

extern RF_SETTINGS rfSettings;

unsigned char packetReceived;
unsigned char packetTransmit; 

unsigned char RxBuffer[64];
unsigned char RxBufferLength = 0;
const unsigned char TxBuffer[6]= {PACKET_LEN, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE};


unsigned char rfMode = 0;

unsigned char transmitting = 0; 
unsigned char receiving = 0; 
unsigned char wor=0;

int mili, sec, burn, state;
uint8_t UID;
uint64_t rxCutdown;
uint8_t rxUID;

void PinInit(void);
uint8_t PacketReceived(char *buffer);
void SendPacket(int ack);

void main( void )
{  
  /* Stop watchdog timer to prevent time out reset  */
  WDTCTL = WDTPW + WDTHOLD; 
  
  _BIS_SR(GIE); 		//turns on interrupts
  
  mili = 0;
  sec = 0;
  burn = 0;
  state = 0;
  //P1REN = BIT2;
  TA1CTL = TASSEL_2 + TACLR + MC_1;
  TA1CCTL0 = CCIE;

  TA1CCR0 = 10000;
  TA1CCTL1 = CCIE;
  TA1CCR1 = 1000;
  
  PinInit();
  XT1_Start(XT1DRIVE_3);
  
  // Initializing UCS
  UCSCTL0 = DCO0 + MOD0;
  UCSCTL1 = DCORSEL_0 + DISMOD;
  UCSCTL2 = FLLD_0 + FLLN1;
  UCSCTL3 = SELREF_0 + FLLREFDIV_0;
  UCSCTL4 = SELA_0 + SELS_0 + SELM_0;
  UCSCTL5 = DIVPA_0 + DIVA_0 + DIVS_0 + DIVM_0;
  UCSCTL6 = XT2OFF + XT1DRIVE_3 + XTS + XT1BYPASS;
  
  SetVCore(3);                            
  ResetRadioCore();
  //Init_FLL(8500000/1000, 8500000/32768);  
  InitRadio();
  
  //InitButtonLeds();
  //GetRfMode();                              // Select RF Operation Mode
  rfMode = PACKET_RX_WOR;
  
 
  switch (rfMode)       
  {
    case PACKET_TX: 
      RfModeTX();   
      break;
    case PACKET_RX: 
      RfModeRX(); 
      break;                      
    case PACKET_RX_WOR: 
      RfModeWOR();
  }  
}

/* void RfModeRX(void)
 *
 * CC430 stays in RX Mode, CPU in LPM3, RF1A core permanently on 
 * LED1 (Green) toggles indicating an RF packet reception */

void RfModeRX(void)
{
  receiving = 1; 
  while (1)
  { 
    ReceiveOn();     
    __bis_SR_register( LPM3_bits + GIE );   
    __no_operation();  
    if(RxBuffer[CRC_LQI_IDX] & CRC_OK)      // Check checksum bit
      P1OUT ^= BIT0;                        // Toggle LED1
  }
}

/* void RfModeTX(void)
 *
 * CC430 stays permanently in TX Mode, periodically transmitting a packet  
 * LED2 (Red) toggles indicating an RF packet transmission */

void RfModeTX(void)
{
  
  while (1)
  {
    transmitting = 1;
    Transmit( (unsigned char*)TxBuffer, sizeof TxBuffer);         
    P3OUT ^= BIT6;
    __delay_cycles(800000);
  }
}

/* void RxModeWOR(void)
 *
 * CC430 stays in WOR mode with CPU in LPM3, RF1A core periodically wakes up 
 * LED1(Green) toggles indicating radio core waking up (EVENT0)
 * LED1&LED2 toggles indicating an RF packet reception */

void RfModeWOR(void)
{
  WriteSingleReg(WOREVT1, 0x87);
  WriteSingleReg(WOREVT0, 0x6B);  
  /* WORCTRL.EVENT1 = 7 => T_EVENT1 = ~1.5 msec */
  WriteSingleReg(MCSM2, 0x00);    
  /* WORCTRL.WOR_RES = 0 (EVENT0 = 34667, RX_TIME = 6) 
     =>  RX timeout  = 34667 * 0.0563 = ~1.96 msec */
  WriteSingleReg(WORCTRL, (7 << 4) | 0); 
  
  WriteSingleReg(IOCFG1, 0x29);             // GDO1 = RF_RDY
  wor = 1;
  while (1)
  {    
    Strobe(RF_SWOR);    
    RF1AIE |= BIT14;              
    __bis_SR_register(LPM3_bits + GIE); 
    __no_operation();
    if(RxBuffer[CRC_LQI_IDX] & CRC_OK)      // Check checksum bit
    {
      //need to add code to actually grab and process received packet.
      //after receiving and acknowledging real cut down signal switch to Tx mode
      //and send an ack that received cut down and that cut down sequence was started
      P3OUT ^= BIT6;
      P1OUT ^= BIT0;
    }
  }  
}
   

#pragma vector=CC1101_VECTOR
__interrupt void CC1101_ISR(void)
{
  switch(__even_in_range(RF1AIV,32))        // Prioritizing Radio Core Interrupt 
  {
    case  0: break;                         // No RF core interrupt pending                                            
    case  2: break;                         // RFIFG0    
    case  4:                                // GDO1 = LNA_PD signal
      RF1AIE &= ~(BIT1+BIT9);
      Strobe(RF_SWOR);                      // Go back to sleep
      P1OUT ^= BIT0;
      break;                         
    case  6: break;                         // RFIFG2
    case  8: break;                         // RFIFG3
    case 10: break;                         // RFIFG4
    case 12: break;                         // RFIFG5
    case 14: break;                         // RFIFG6          
    case 16: break;                         // RFIFG7
    case 18: break;                         // RFIFG8
    case 20:                                // RFIFG9 
      if(receiving || wor)			            // RX end of packet
      {
        RF1AIE &= ~(BIT1+BIT9);
        /* Read the length byte from the FIFO        */
        RxBufferLength = ReadSingleReg( RXBYTES ); 
        /* Read RX packet from the RX FIFO        */
        ReadBurstReg(RF_RXFIFORD, RxBuffer, RxBufferLength); 
        
        /* Stop here to see contents of RxBuffer */   
        __no_operation(); 
      }
      else if(transmitting)		              // TX end of packet
      {
        RF1AIE &= ~BIT9;                    // Disable TX end-of-packet interrupt        
        transmitting = 0; 
      }
      else  while (1); 			                // trap 
      __bic_SR_register_on_exit(LPM3_bits);     
      break;
    case 22: break;                         // RFIFG10
    case 24: break;                         // RFIFG11
    case 26: break;                         // RFIFG12
    case 28: break;                         // RFIFG13
    case 30:                                // WOR_EVENT0
      P1OUT ^= BIT0;
      RF1AIE |= BIT9 + BIT1;                
      RF1AIFG &= ~(BIT9 + BIT1);   	    
      RF1AIES |= BIT9;                      // Falling edge of RFIFG9
      RF1AIFG &= ~BIT9;                     // Clear a pending interrupt
      RF1AIE  |= BIT9;                      // Enable the interrupt      
      Strobe( RF_SRX );      
      break;                         
    
    case 32:  break;                         // RFIFG15
  } 
}

 

void InitRadio(void)
{
  /* Set the High-Power Mode Request Enable bit so LPM3 can be entered
     with active radio enabled */
  PMMCTL0_H = 0xA5;
  PMMCTL0_L |= PMMHPMRE_L; 
  PMMCTL0_H = 0x00; 
  
  WriteRfSettings(&rfSettings);             // Write settings to RF registers 
  WriteSinglePATable(PATABLE_VAL);          // Write to Power Amplifier Table
}



void Transmit(unsigned char *buffer, unsigned char length)
{
  RF1AIES |= BIT9;                          
  RF1AIFG &= ~BIT9;                         // Clear pending interrupts
  RF1AIE |= BIT9;                           // Enable TX end-of-packet interrupt
  
  WriteBurstReg(RF_TXFIFOWR, buffer, length);     
  
  Strobe( RF_STX );                         // Strobe STX   
}

void ReceiveOn(void)
{  
  RF1AIES |= BIT9;                          // Falling edge of RFIFG9
  RF1AIFG &= ~BIT9;                         // Clear a pending interrupt
  RF1AIE  |= BIT9;                          // Enable the interrupt 
  
  // Radio is in IDLE following a TX, so strobe SRX to enter Receive Mode
  Strobe( RF_SRX );                         // Strobe SRX   
}

void ReceiveOff(void)
{
  RF1AIE &= ~BIT9;                          // Disable RX interrupts
  RF1AIFG &= ~BIT9;                         // Clear pending IFG

  // It is possible that ReceiveOff is called while radio is receiving a packet.
  // Therefore, it is necessary to flush the RX FIFO after issuing IDLE strobe 
  // such that the RXFIFO is empty prior to receiving a packet.
  Strobe( RF_SIDLE );
  Strobe( RF_SFRX  );                       
}

  
//void InitButtonLeds(void)
//{
//  /* Set up the button as interruptible  */
//  P1DIR &= ~BIT7;
//  P1REN |= BIT7;
//  P1IES |= BIT7;
//  P1IFG = 0;
//  P1OUT |= BIT7;
//  P1IE  |= BIT7; 
//
//  /* Initialize Port J */
//  PJOUT = 0x00;
//  PJDIR = 0xFF; 
//
//  /* Set up LEDs */
//  P1OUT &= ~BIT0;
//  P1DIR |= BIT0;
//  P3OUT &= ~BIT6;
//  P3DIR |= BIT6;
//}

/*******************************************************************************
 * void GetRfMode(void) 
 * prompts user to cycle through three modes of RF operations, RX, TX, and WOR, 
 * by pressing a push button and lock in the selection by holding down the same
 * push button. Two LEDs are used to indicate current selection.
 * LED 0 = Green, LED 1 = Red 
 *               LED 0 Off        LED 0 On
 *            ____________________________________
 * LED 1 Off |  No Selection       RX Mode        |       
 * LED 1 On  |     TX Mode         WOR Mode       |
 *            ------------------------------------
 *
 ******************************************************************************/

void GetRfMode(void)
{
  unsigned long i;
  unsigned char mode_set = 0;

  while (!mode_set)
  {
    __bis_SR_register(LPM3_bits + GIE);
    __no_operation(); 
    P1IE &= ~BIT7;
    i = 0;
    while (i < 10000)
    {
      __delay_cycles(250);                  // Button debounce delay 
      if (P1IN & BIT7)                      // Button already released
      {
        switch(rfMode)
        {
        case MODE_NOT_SET:
        case PACKET_RX_WOR:
          rfMode = PACKET_RX;          
          P1OUT |= BIT0;                    // Turn on LED 0
          P3OUT &= ~BIT6;                   // Turn off LED 1
          
          break;
        case PACKET_RX:
          rfMode = PACKET_TX;
          P1OUT &= ~BIT0;                   // Turn off LED 0
          P3OUT |= BIT6;                    // Turn on LED 1     
          break;
        case PACKET_TX:
          rfMode = PACKET_RX_WOR;
          P1OUT |= BIT0;                    // Turn on LED 0
          P3OUT |= BIT6;                    // Turn on LED 1
          break;
        } 
      
        break;
      }
      else
        i++;
    }
    if (i==10000)                           // If button held long enough
    {
      mode_set = 1;      
      P1OUT &= ~BIT0;                       // Turn off LEDs
      P3OUT &= ~BIT6;         
    }
    else
      P1IE |= BIT7;                         // Re-enable S2 interrupts
  }
}

#pragma vector=PORT1_VECTOR
__interrupt void PORT1_ISR(void)
{
  switch(__even_in_range(P1IV, 16))
  {
    case  0: break;
    case  2: break;                         // P1.0 IFG
    case  4: break;                         // P1.1 IFG
    case  6: break;                         // P1.2 IFG
    case  8: break;                         // P1.3 IFG
    case 10: break;                         // P1.4 IFG
    case 12: break;                         // P1.5 IFG
    case 14: break;                         // P1.6 IFG
    case 16:                                // P1.7 IFG         
      __bic_SR_register_on_exit(LPM3_bits); // Exit active    
      break;
  }
}

void PinInit(void)
{
  P1DIR = 0xFE; // pin1.0 will be set to output at time of cutdown
  P1OUT = 0x00; // pin1.0 will be set at time of cutdown
  
  P2DIR = 0xE1; //Unused pins will beset to output with '0' for an output
  P2OUT = 0x00;
  P2REN = 0x1E; //putting pull down resistance on the inputs from dipswitch
  
  P3DIR = 0xFF;
  P3OUT = 0x00;
  
  P4DIR = 0xFF; //All pins are output, those that are not connected will be kept with '0' for an output
  P4OUT = 0x00;	
  
  P5DIR = 0xFF;
  P5OUT = 0x00;
  P5SEL = 0x03; //Setting 5.0 and 5.1 for XT1 mode
  UCSCTL6 |= XCAP_3; // Internal load cap
}

uint8_t PacketReceived(char *buffer)
{
	/* Need to determine what exactly is being sent,
	parse the actual cutdown code from the UID number,
	and then compare the both of them (Chris 1-20-12)*/
	
	// parse rxpacket
        //need to write a for loop to load rxCutdown and rxUID
	rxCutdown = 0;//whatever portion of rxpacket is the cutdown code
	rxUID = 0;//whatever portion of rxpacket is the UID
	
	if (rxCutdown == 0x435554444F574E) //0x435554444F574E is ASCII for CUTDOWN
	{
		if (rxUID == UID)
		{
			//call cutter sequence here
			return SUCCESS;
		}
		else
		{
			return FAIL;
		}
	}
	return FAIL;
}

void SendPacket(int ack)
{
	
}